#include <iostream>
#include <string_view>
#include <memory>

void Initialize() {
  int units_sold1 = 0;
  int units_sold2 = {0};
  int units_sold3{0};  // 如果使用初始化列表有丢失信息的风险，编译器会报错
  int units_sold4(0);
  int units_sold;  // 定义于函数体内的内置类型的对象如果没有被初始化，则其值未定义
  std::cout << units_sold << std::endl;
}

void Reference() {
  int ival = 1024;
  // 使用术语“引用”其实指的是“左值引用”
  // 引用本质上不是一个对象
  int &ref_val = ival;  // refVal 指向 ival
  std::cout << &ref_val <<std::endl;
  std::cout << &ival <<std::endl;
  int &ref_ref_val = ref_val;
  std::cout << &ref_ref_val <<std::endl;

}

void Pointer() {
  int *p1 = 0;
  int *p2 = NULL;
  int *p3 = nullptr;
  void *pVoid = nullptr;
}

void PointerAndConst() {
  // 指向常量的指针
  const double pi = 3.14;
  const double *ptr = &pi;  // 指向常量的指针
  double dval = 3.14;  // 允许一个指向常量的指针指向一个非常量的对象
  ptr = &dval;  // 不能通过ptr改变dval的值

  // const指针，制指针是一个常量，必须初始化，一旦初始化完成不能改变
  int err_numb = 0;
  /**
   * 从右往左读：
   * 离cur_err最近的符号是const，意味着cur_err本身是一个常量对象
   * 对象的类型由声明的其余部分确定：
   * 声明符的下一个符号是*，意思是 cur_err是一个常量指针
   * 最后确定了常量指针指向的是一个int对象
   */
  int *const cur_err = &err_numb;  // cur_err将一直指向err_numb
  const double *const pip = &pi;  // pip是一个指向常量对象的常量指针
  *cur_err = 0;  // 指针是常量并不意味着不能通过指针修改其所指对象的值

  /**
   * 总结：
   * 从右往左读：
   * const double *const ptr = pi;
   * 顶层的const可以表示任意的对象是常量：对任何数据类型都适用
   * 底层的const指针则与指针和引用等复合类型的基本类型有关
   * 特殊的：指针类型既可以是顶层const也可以是底层const
   */

}

int main() {
//  int value;
//  while (std::cin >> value) {
//    std::cout << value << std::endl;
//  }
//  Initialize();
//  Reference();
  Pointer();
}